# -*- coding: utf-8 -*-
"""
Author:Lu
E-mail:luliangce@gmail.com
Created:2018/3/31
Update:

用户模型,封装以下操作:

--资料--
1.上传头像
#.

"""
from __future__ import unicode_literals
from Abstract import Base
from Account import Account
import json
import time
from log import ls
logger = ls.logger


class User(Base):

    def __init__(self, username=None, password=None):
        self.username = username
        self.password = password
        super(User, self).__init__()

        if username and password:
            if self.login(username=username, password=password):
                logger.info("登录成功")
            else:
                raise Exception(u"登录失败")
            if self.get_profile():
                logger.info("资料获取成功")
            else:
                logger.info("获取资料失败")

    def uploadHeadPic(self, pic):
        """修改头像

        Arguments:
            pic {str} -- 图片相对与根目录的路径

        Returns:
            [bool] -- 是否替换成功
        """

        url = "https://www.instagram.com/accounts/web_change_profile_picture/"
        try:
            # 如果接收到的是图片路径
            f = open(pic, "rb")
        except:
            logger.info("图片路径不正确")
            return False
        files = {
            "profile_pic": ("profilepic.jpg", f, "image/jpeg")
        }
        resp = self.post(url, file=files)
        try:
            j = resp.json()
            return j.get("changed_profile") and j.get("has_profile_pic")
        except:
            logger.info("头像替换失败")
            pass
        return False

    def uploadPic(self, pic, caption=""):
        """发布图片

        Arguments:
            pic {str} -- [图片路径]
            caption {str} -- 说明文字

        Returns:
            [bool] -- 是否发布成功
        """

        url = "https://www.instagram.com/create/upload/photo/"
        upload_id = str(int(time.time()*1000))
        param = {
            "upload_id": upload_id,
            "media_type": "1"
        }
        f = open(pic, "rb")
        files = {"photo": ("photo.jpg", f, "image/jpeg")}
        resp = self.post(url, data=param, file=files)
        try:
            if resp.json().get("status", "") == "ok":
                return self.__uploadConfigure(upload_id, caption)
        except:
            pass
        return False

    def __uploadConfigure(self, upload_id, caption=""):
        """私有方法,图片上传的确认步骤,传入图片配文

        Arguments:
            upload_id {[str]} -- 图片上传ID

        Keyword Arguments:
            caption {str} -- 说明文字 (default: {""})

        Returns:
            [bool] -- [是否上传成功]
        """

        url = "https://www.instagram.com/create/configure/"
        param = {
            "upload_id": upload_id,
            "caption": caption
        }
        resp = self.post(url, data=param)
        try:
            return resp.json().get("status", "") == "ok"
        except:
            return False

    def changeProfile(self, profile):
        """修改资料

        Arguments:
            profile {dict} -- 一个包含需要修改项目的字典,对应字段:
            {
            "first_name": "全名",
            "email": "电子邮件",
            "username": "登录用户名",
            "phone_number": "手机号码" 不要修改这个,会触发短信验证,
            "gender": "性别.1男2女",
            "biography": "个人简介",
            "external_url": "网站",
            "chaining_enabled": "类似帐户推荐", on开启,空白关闭,
            "private_account": "设为私密账户",默认关闭,开启需要输入 on,空白关闭,
        }

        """
        url = "https://www.instagram.com/accounts/edit/"
        form = {
            "first_name": "",
            "email": "",
            "username": "",
            "phone_number": "",
            "gender": "",
            "biography": "",
            "external_url": "",
            "chaining_enabled": "",
            "private_account": "",
        }
        if not self.profile:
            if not self.get_profile:
                self.profile = {}
                logger.info("获取原始资料失败,缺省参数可能会造成修改失败")
        else:
            for k, v in self.profile.items():
                if k in form:
                    form[k] = v
        form.update(profile)  # 将用户设置参数更新到表单中
        resp = self.post(url, data=form, header={"referer": url})
        try:
            r = resp.json()["status"] == "ok"  # 如果修改成功,刷新资料
            if r:
                self.get_profile()
            return r
        except:
            return False

    def searchTopic(self):
        pass

    def follow(self, target_id):
        """关注某一个用户

        Arguments:
            target_id {[str]} -- 待关注用户的id

        Returns:
            [{bool}] -- 是否关注成功
        """

        logger.info("正在关注 {}".format(target_id))
        url = "https://www.instagram.com/web/friendships/{}/follow/".format(
            target_id)

        resp = self.post(url=url)
        try:
            response = resp.json()
            return response.get("result") == "following"
        except:
            return False
        #{"result": "following", "status": "ok"}

    def exploreTag(self, tagName):
        """关注标签下第一页的用户

        Arguments:
            tagName {str} -- 标签英文名,小写无空格,如"football"

        Returns:
            [{list},{bool},{str}] -- 用户列表,是否有下一页,分页标记 
        """

        url = "https://www.instagram.com/explore/tags/{}/?__a=1".format(
            tagName)
        resp = self.get(url, is_ajax=True)
        _, users, has_next, cursor = self.__parseTag(resp)

        return users, has_next, cursor

    def get_users(self, tagName, max_page=2):
        u = set()
        for users in self.deepExploreTag(tagName, max_page):
            u = u.union(users)
        return list(u)

    def deepExploreTag(self, tagName, max_page=5):
        """深度探索标签,将发帖用户添加到集合中

        Arguments:
            tagName {str} -- 标签名称

        Keyword Arguments:
            max_page {int} -- 最大页数 (default: {5})

        Returns:
            [set] -- 发帖的用户id集合(无重复)
        """
        page = 1
        logger.info("当前页面{}".format(page))
        users, has_next, cursor = self.exploreTag(tagName)
        yield users
        while has_next:
            page += 1
            if page >= max_page:
                break
            logger.info("当前页面{}".format(page))
            new_user, has_next, cursor = self.__dpe(tagName, cursor)
            yield new_user

    def __dpe(self, tagName, cursor):
        url = "https://www.instagram.com/graphql/query/"
        param = {
            "query_hash": "ded47faa9a1aaded10161a2ff32abb6b",
            "variables": json.dumps({
                "tag_name": tagName,
                "first": "2",
                "after": cursor
            })
        }
        resp = self.get(url, data=param)
        _, users, has_next, cursor = self.__parseTag(resp)
        return users, has_next, cursor

    def followTag(self, tagName, max_page=2):
        """连续关注30~40个之后会提示稍后几分钟再试
        关注标签下最新的用户
        Arguments:
            tagName {str} -- 标签英文名,小写无空格,如"football"
            deep {bool} -- 是否翻页继续关注

        """
        users = self.deepExploreTag(tagName)
        for userset in users:
            for user in userset:
                if self.follow(user):
                    logger.info("{} 关注成功".format(user))
                else:
                    logger.info("{} 关注失败".format(user))

                time.sleep(0.1)

    def __parseTag(self, resp):
        try:
            d = json.loads(resp.content).get("graphql", {}).get("hashtag")
            if not d:
                d = json.loads(resp.content).get("data", {}).get("hashtag")
        except:
            return
        name = d.get("name")
        pageinfo = d.get(
            "edge_hashtag_to_media", {}).get("page_info", {})
        has_next = pageinfo.get("has_next_page", False)
        end_cursor = pageinfo.get("end_cursor")
        edges = d.get("edge_hashtag_to_media", {}).get("edges", [])
        users = self.__parseNode(edges)
        return name, users, has_next, end_cursor

    def __parseNode(self, nodes):
        """ 返回数据中所有的发布人id """
        owners = set()
        for node in nodes:
            # logger.info(node
            owner = node.get("node", {}).get("owner", {}).get("id", None)
            owners.add(owner)
        return owners


def main():
    u = User("testliangce123", "liangcea")
    u.followTag("dance")


if __name__ == '__main__':
    main()
